package pers.cj.pdos.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import pers.cj.pdos.entity.*;
import pers.cj.pdos.exception.CustomException;
import pers.cj.pdos.mapper.*;
import pers.cj.pdos.service.IHouseOutService;
import pers.cj.pdos.utils.PdosUtils;
import pers.cj.pdos.utils.GoodsUtil;
import pers.cj.pdos.utils.Utils;
import pers.cj.pdos.utils.UuidUtils;
import pers.cj.pdos.vo.HouseOutGoodsVo;
import pers.cj.pdos.vo.HouseOutPacketVo;
import pers.cj.pdos.vo.HouseOutVo;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author chenj
 * @since 2020-02-21
 */
@Service
public class HouseOutServiceImpl extends ServiceImpl<HouseOutMapper, HouseOut> implements IHouseOutService {
    @Autowired
    HouseOutMapper houseOutMapper;
    @Autowired
    HouseOutGoodsMapper houseOutGoodsMapper;
    @Autowired
    HouseOutPacketMapper houseOutPacketMapper;
    @Autowired
    HouseOutPacketGoodsMapper houseOutPacketGoodsMapper;
    @Autowired
    HouseWaitInMapper houseWaitInMapper;
    @Autowired
    HouseWaitInGoodsMapper houseWaitInGoodsMapper;

    @Autowired
    GoodsSnMapper goodsSnMapper;

    @Autowired
    HouseWaitOutMapper houseWaitOutMapper;
    @Autowired
    HouseWaitOutGoodsMapper houseWaitOutGoodsMapper;
    @Autowired
    HouseWaitOutPacketMapper houseWaitOutPacketMapper;

    @Autowired
    GoodsStockMapper goodsStockMapper;
    @Autowired
    GoodsSnLogMapper goodsSnLogMapper;
    @Autowired
    GoodsTransferMapper goodsTransferMapper;
    @Autowired
    GoodsTransferGoodsMapper goodsTransferGoodsMapper;
    @Autowired
    HouseMapper houseMapper;
    @Autowired
    SettAccountMapper settAccountMapper;

    @Override
    public boolean checkNo(String no, String companyId) {
        return houseOutMapper.selectCount(new QueryWrapper<HouseOut>().eq("company_id",companyId).eq("no",no)) > 0;
    }

    @Override
    public void insert(HouseOut houseOut, List<HouseOutGoods> houseOutGoodsList, List<GoodsSn> goodsSnList, List<GoodsSnLog> goodsSnLogList,
                       List<HouseOutPacket> houseOutPacketList,List<HouseOutPacketGoods> houseOutPacketGoodsList) {
        houseOutMapper.insert(houseOut);

        if (!Utils.isEmpty(houseOutGoodsList)) {
            houseOutGoodsMapper.insertBatch(houseOutGoodsList);
        }

        if (!Utils.isEmpty(houseOutPacketList)) {
            houseOutPacketMapper.insertBatch(houseOutPacketList);
            houseOutPacketGoodsMapper.insertBatch(houseOutPacketGoodsList);
        }

        HouseOutVo vo = houseOutMapper.getVoById(houseOut.getId());

        Boolean locking = houseMapper.selectById(vo.getHouseId()).getLocking();
        if (locking!=null && locking) {
            throw new CustomException("仓库被锁定，无法出库");
        }

        //出库 运费 余额-
        if (!Utils.isEmpty(vo.getSettAccountId()) && vo.getDeliveryAmt()!= null){
            settAccountMapper.addBalance(vo.getDeliveryAmt().negate(), vo.getSettAccountId());
        }

        //处理待出库单
        processHouseWaitOut(1,vo);

        //减少库存
        processStock(1,vo);


        if (!Utils.isEmpty(goodsSnList)) {
            goodsSnMapper.outByList(vo.getHouseId(),goodsSnList);
            goodsSnLogMapper.insertBatch(goodsSnLogList);
        }
        processGoodsTransfer_HouseWaitIn(1,vo);
    }

    @Override
    public void close(HouseOut houseOut) {
        HouseOutVo vo = houseOutMapper.getVoById(houseOut.getId());

        //出库作废 运费 余额+
        if (!Utils.isEmpty(vo.getSettAccountId()) && vo.getDeliveryAmt()!= null){
            settAccountMapper.addBalance(vo.getDeliveryAmt(), vo.getSettAccountId());
        }

        //处理库存
        processStock(2, vo);

        //关闭进货单需要sn号需要处与在库状态
        List<GoodsSn> list = PdosUtils.genGoodsSnList(vo.getHouseOutGoodsVoList());
        if (!Utils.isEmpty(list)) {
            goodsSnMapper.inByList(vo.getHouseId(), list);
        }

        //处理待入库单
        processHouseWaitOut(2,vo);

        //关闭单据本身
        houseOut.setClose(true);
        houseOutMapper.updateById(houseOut);

        if (vo.getType()==3){
            //说明：业务流程上，如果是调拨单作废的流程是，首先要先作废对应的入库单，然后才能作废对应的出库单，最后作废调拨单本身。
            //所以走到这里表明，对应的入库单已经作废了。 此时作废出库单，就要作废对应的待入库单
            HouseWaitIn houseWaitIn = new HouseWaitIn();
            houseWaitIn.setClose(true);
            houseWaitInMapper.update(houseWaitIn, new QueryWrapper<HouseWaitIn>().eq("house_out_id",vo.getId()));

            long wait = houseWaitOutGoodsMapper.countWaitOutNumber(vo.getHouseWaitOutId());
            long number = goodsTransferGoodsMapper.countNumber(vo.getGoodsTransferId());
            GoodsTransfer goodsTransfer = new GoodsTransfer();
            goodsTransfer.setId(vo.getGoodsTransferId());
            if (wait == 0) {
                //待出库单全部出库
                goodsTransfer.setOutStatus(3);
            } else if (wait == number){//全部等待出库
                goodsTransfer.setOutStatus(1);
            } else {
                goodsTransfer.setOutStatus(2);
            }
            //改变调拨单的入库状态
            goodsTransferMapper.updateById(goodsTransfer);
        }

    }

    /**
     * 处理调拨单时的待入库单和调拨单出库状态
     * @param type
     * @param vo
     */
    void processGoodsTransfer_HouseWaitIn(int type , HouseOutVo vo) {
        if (vo.getType() != 3) {
            return;
        }

        GoodsTransfer db = goodsTransferMapper.selectById(vo.getGoodsTransferId());
        String houseId = db.getInHouseId();//获取入库仓库id

        if (type == 1) {//新增调拨时，需要新增待入库单
            HouseWaitIn houseWaitIn = new HouseWaitIn();
            houseWaitIn.setId(UuidUtils.getUUID());
            houseWaitIn.setHouseOutId(vo.getId());
            houseWaitIn.setGoodsTransferId(vo.getGoodsTransferId());
            houseWaitIn.setHouseId(houseId);
            houseWaitIn.setClose(false);
            houseWaitIn.setStatus(1);//待入库
            houseWaitIn.setType(3);//设置类型为调拨
            houseWaitIn.setCompanyId(vo.getCompanyId());
            houseWaitIn.setTime(vo.getTime());
            houseWaitInMapper.insert(houseWaitIn);

            //当时调拨单时，出库一次就新增一个对应的入库单
            List<HouseWaitInGoods> houseWaitInGoodsList = new ArrayList<>();
            for (HouseOutGoodsVo hgv : vo.getHouseOutGoodsVoList()) {
                HouseWaitInGoods houseWaitInGoods = new HouseWaitInGoods();
                houseWaitInGoods.setId(UuidUtils.getUUID());
                houseWaitInGoods.setHouseWaitInId(houseWaitIn.getId());
                houseWaitInGoods.setGoodsTransferGoodsId(hgv.getGoodsTransferGoodsId());
                houseWaitInGoods.setGoodsId(hgv.getGoodsId());
                houseWaitInGoods.setHasInNumber(new BigDecimal("0"));
                houseWaitInGoods.setWaitInNumber(hgv.getNumber());
                houseWaitInGoods.setNumber(hgv.getNumber());
                houseWaitInGoods.setUnitId(hgv.getUnitId());
                houseWaitInGoods.setTimes(hgv.getTimes());
                houseWaitInGoods.setCompanyId(vo.getCompanyId());
                houseWaitInGoodsList.add(houseWaitInGoods);
            }
            houseWaitInGoodsMapper.insertBatch(houseWaitInGoodsList);
        }


        long wait = houseWaitOutGoodsMapper.countWaitOutNumber(vo.getHouseWaitOutId());
        long number = goodsTransferGoodsMapper.countNumber(vo.getGoodsTransferId());
        GoodsTransfer goodsTransfer = new GoodsTransfer();
        goodsTransfer.setId(vo.getGoodsTransferId());
        if (wait == 0) {
            //待出库单全部出库
            goodsTransfer.setOutStatus(3);
        } else if (wait == number){//全部等待出库
            goodsTransfer.setOutStatus(1);
        } else {
            goodsTransfer.setOutStatus(2);
        }
        //改变调拨单的入库状态
        goodsTransferMapper.updateById(goodsTransfer);

    }


    /**
     * 处理库存
     * @param type 1新增出库单，作废单据
     * @param vo
     */
    private void processStock(int type, HouseOutVo vo) {
        String houseId = vo.getHouseId();
        String companyId = vo.getCompanyId();

        List<GoodsStock> goodsStockList = new ArrayList<>();
        GoodsUtil goodsUtil = new GoodsUtil(houseId,vo.getHouseOutGoodsVoList(), vo.getHouseOutPacketVoList());
        for ( Map.Entry<String,BigDecimal> entry: goodsUtil.getAllGoodsNumberMap().entrySet()) {
            BigDecimal number = entry.getValue();
            if (type == 1) {
                //销售是减少库存的动作，所以需要减少库存
                number = number.negate();
            }

            GoodsStock goodsStock = new GoodsStock();
            goodsStock.setId(UuidUtils.getUUID());
            goodsStock.setGoodsId(entry.getKey());
            goodsStock.setHouseId(houseId);
            goodsStock.setNum(number);
            goodsStock.setTime(new Date());
            goodsStock.setCompanyId(companyId);
            goodsStockList.add(goodsStock);
        }

        goodsStockMapper.insertBatch(goodsStockList);
    }

    /**
     * 处理待出库当
     * @param type 1新增单据，作废单据
     * @param vo
     */
    private void processHouseWaitOut(int type, HouseOutVo vo) {
        if (!Utils.isEmpty(vo.getHouseOutGoodsVoList())) {
            List<HouseWaitOutGoods> newList = new ArrayList<>();
            for (HouseOutGoodsVo hgv : vo.getHouseOutGoodsVoList()) {
                HouseWaitOutGoods hwg = new HouseWaitOutGoods();
                hwg.setId(hgv.getHouseWaitOutGoodsId());
                hwg.setHouseWaitOutId(vo.getHouseWaitOutId());
                hwg.setGoodsId(hgv.getGoodsId());
                hwg.setHasOutNumber(type == 1 ? hgv.getNumber() : hgv.getNumber().negate());
                hwg.setWaitOutNumber(type == 1 ? hgv.getNumber().negate() : hgv.getNumber());
                hwg.setNumber(hgv.getNumber());
                hwg.setUnitId(hgv.getUnitId());
                hwg.setTimes(hgv.getTimes());
                hwg.setCompanyId(vo.getCompanyId());
                newList.add(hwg);
            }
            houseWaitOutGoodsMapper.insertBatch(newList);
        }

        if (!Utils.isEmpty(vo.getHouseOutPacketVoList())) {
            List<HouseWaitOutPacket> newList = new ArrayList<>();
            for (HouseOutPacketVo hgv : vo.getHouseOutPacketVoList()) {
                HouseWaitOutPacket hwg = new HouseWaitOutPacket();
                hwg.setId(hgv.getHouseWaitOutPacketId());
                hwg.setHouseWaitOutId(vo.getHouseWaitOutId());
                hwg.setSalePacketId(hgv.getSalePacketId());
                hwg.setPacketId(hgv.getPacketId());
                hwg.setPacketNo(hgv.getPacketNo());
                hwg.setPacketName(hgv.getPacketName());
                hwg.setHasOutNumber(type == 1 ? hgv.getNumber() : hgv.getNumber().negate());
                hwg.setWaitOutNumber(type == 1 ? hgv.getNumber().negate() : hgv.getNumber());
                hwg.setNumber(hgv.getNumber());
                hwg.setCompanyId(vo.getCompanyId());
                newList.add(hwg);
            }
            houseWaitOutPacketMapper.insertBatch(newList);
        }


        long totalWaitNumber = houseWaitOutGoodsMapper.countWaitOutNumber(vo.getHouseWaitOutId()) + houseWaitOutPacketMapper.countWaitOutNumber(vo.getHouseWaitOutId());
        long number = houseWaitOutPacketMapper.countNumber(vo.getHouseWaitOutId()) + houseWaitOutPacketMapper.countNumber(vo.getHouseWaitOutId());

        HouseWaitOut houseWaitOut = new HouseWaitOut();
        houseWaitOut.setId(vo.getHouseWaitOutId());
        if (totalWaitNumber == 0) {
            //待出库单全部出库
            houseWaitOut.setStatus(3);
        } else {
            if (totalWaitNumber == number) {
                houseWaitOut.setStatus(1);
            } else {
                houseWaitOut.setStatus(2);
            }
        }

        houseWaitOutMapper.updateById(houseWaitOut);
    }


    @Override
    public List<HouseOutVo> listVo(String companyId,
                                   Integer page,
                                   Integer limit,
                                   Boolean close,
                                   Integer type,
                                   String search,
                                   String no,
                                   String linkNo,
                                   String goodsName,
                                   String remark,
                                   String unitName,
                                   Date makeTime1,
                                   Date makeTime2,
                                   String makeUserId,
                                   String userStoreId,
                                   String userId,
                                   Date date1,
                                   Date date2,
                                   String storeId,
                                   String houseId) {
        return houseOutMapper.listVo(companyId,
                Utils.genPage(page,limit),
                limit,
                close,
                type,
                search,
                no,
                linkNo,
                goodsName,
                remark,
                unitName,
                makeTime1,
                makeTime2,
                makeUserId,
                userStoreId,
                userId,
                date1,
                date2,
                storeId,
                houseId);
    }

    @Override
    public long count(String companyId,
                      Boolean close,
                      Integer type,
                      String search,
                      String no,
                      String linkNo,
                      String goodsName,
                      String remark,
                      String unitName,
                      Date makeTime1,
                      Date makeTime2,
                      String makeUserId,
                      String userStoreId,
                      String userId,
                      Date date1,
                      Date date2,
                      String storeId,
                      String houseId) {
        return houseOutMapper.count(companyId,
                close,
                type,
                search,
                no,
                linkNo,
                goodsName,
                remark,
                unitName,
                makeTime1,
                makeTime2,
                makeUserId,
                userStoreId,
                userId,
                date1,
                date2,
                storeId,
                houseId);
    }

    @Override
    public HouseOutVo getVoById(String id) {
        HouseOutVo entity = houseOutMapper.getVoById(id);
        return entity;
    }

    @Override
    public List<HouseOutVo> listVoByIds(List<String> ids) {
        return houseOutMapper.listVoByIds(ids);
    }

    @Override
    public List<HouseOutVo> listVoByHouseWaitOut(String houseWaitOutId) {
        return houseOutMapper.listVoByHouseWaitOut(houseWaitOutId);
    }

    @Override
    public boolean checkByLinkId(String linkId) {
        return houseOutMapper.countByLinkId(linkId) > 0;
    }

    @Override
    public boolean checkClose(HouseOut houseOut) {
        return houseOutMapper.selectCount(new QueryWrapper<HouseOut>().eq("id",houseOut.getId()).eq("close",true)) > 0;
    }
}
